package com.hymjweb.demo.config.shiro;

import com.hymjweb.demo.framework.sys.SysConstant;
import com.hymjweb.demo.hymj.system_maintenance.permission.bean.PermissionPojo;
import com.hymjweb.demo.hymj.system_maintenance.permission.service.PermissionService;
import com.hymjweb.demo.hymj.system_maintenance.role.bean.RolePojo;
import com.hymjweb.demo.hymj.system_maintenance.role.service.RoleService;
import com.hymjweb.demo.hymj.system_maintenance.role_permission.bean.RolePermissionPojo;
import com.hymjweb.demo.hymj.system_maintenance.role_permission.service.RolePermissionService;
import com.hymjweb.demo.hymj.system_maintenance.user.bean.XtUserPojo;
import com.hymjweb.demo.hymj.system_maintenance.user.service.XtUserService;
import com.hymjweb.demo.hymj.system_maintenance.user_role.bean.UserRolePojo;
import com.hymjweb.demo.hymj.system_maintenance.user_role.service.UserRoleService;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;

import java.util.*;

/**
 * @BelongsProject: demo
 * @BelongsPackage: com.hymjweb.demo.config.shiro
 * @Author: luoge
 * @CreateTime: 2021-03-23 16:17
 * @Description:
 */
public class MyShiroRealm extends AuthorizingRealm {

    @Autowired
    @Lazy
    private XtUserService xtUserService;

    @Autowired
    @Lazy
    private UserRoleService userRoleService;

    @Autowired
    @Lazy
    private RoleService roleService;

    @Autowired
    @Lazy
    private RolePermissionService rolePermissionService;

    @Autowired
    @Lazy
    private PermissionService permissionService;

    /**
     * 认证方法
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        // 待认证的登录对象
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;

        // 获得从表单传过来的用户名(注意这个用户是Mobile来代替的)
        String mobile = token.getUsername();

        // 根据用户名称获取用户对象
        XtUserPojo userPojo = xtUserService.getUserPojoByMoible(mobile);

        if(userPojo==null){
            throw new UnknownAccountException("登录用户不存!");
        }

        if(userPojo.getIsLockId().longValue() == SysConstant.XT_DIC_YES_NO.YES.getId()){
            throw new LockedAccountException("账号已经锁定!");
        }

        // 认证的实体信息，可以是对象也可以具体的某个属性
        Object principal = userPojo;
        // 用户加密后的密码
        Object credentials = userPojo.getPassword();
        // 密码盐值
        String credentialSalt = userPojo.getSalt();

        // 当前realm对象名称
        String realmName = this.getName();

        // 创建SimpleAuthenticationInfo对象，并且把username(本例中是mobile)和password等信息封装到里面
        // 密码的比对是Shiro帮助我们完成的,见ShiroConfig中的密码匹配器的配置
        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(principal,credentials,ByteSource.Util.bytes(credentialSalt),realmName);

        return info;
    }



    /**
     * 授权方法
     * @param principalCollection
     * 1.subject.hasRole(“admin”) 或 subject.isPermitted(“admin”)：自己去调用这个是否有什么角色或者是否有什么权限的时候；
     * 2.@RequiresRoles("admin") ：在方法上加注解的时候；
     * 3.[@shiro.hasPermission name = "admin"][/@shiro.hasPermission]：在页面上加shiro标签的时候，即进这个页面的时候扫描到有这个标签的时候。
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {

        // 从principalCollection中获取用户信息
        Object principal = principalCollection.getPrimaryPrincipal();

        XtUserPojo xtUserPojo = (XtUserPojo) principal;

        // 登录拥有的角色
        Set<String> roles = new HashSet<>();
        // 登录用户拥有的授权资源
        Set<String> permissions = new HashSet<>();


        // 根据据用户ID查询对应的用户角色关联对象,注意判空
        List<UserRolePojo> userRolePojoList = userRoleService.queryUserRoleByUserId(xtUserPojo.getId());
        if(userRolePojoList!=null && !userRolePojoList.isEmpty()){
            StringBuffer userRoleIdBuffer = new StringBuffer();
            for(UserRolePojo userRolePojo: userRolePojoList){
                if(userRolePojo.getRoleId()!=null && !userRolePojo.getRoleId().isEmpty()){
                    userRoleIdBuffer.append("'" + userRolePojo.getRoleId() + "',");
                }
            }

            String userRoleIds = null;
            if(userRoleIdBuffer.length()>SysConstant.INT_ZERO){
                userRoleIds = userRoleIdBuffer.substring(0,userRoleIdBuffer.length()-1);
            }

            if(userRoleIds!=null){

                List<RolePojo> rolePojoList = roleService.getRolePojoByIds(userRoleIds);

                if(rolePojoList!=null && !rolePojoList.isEmpty()){
                    for(RolePojo rolePojo : rolePojoList){
                        roles.add(rolePojo.getName());
                    }
                }

                // 下面根据角色 id，到角色资源表中加载对应的授权资源 id
                List<RolePermissionPojo> rolePermissionPojoList = rolePermissionService.getRolePermissionListByRoleIds(userRoleIds);

                if(rolePermissionPojoList!=null && !rolePermissionPojoList.isEmpty()){
                    Set<String> permissionIdSet = new HashSet<>();
                    for(RolePermissionPojo rolePermissionPojo : rolePermissionPojoList){
                        permissionIdSet.add(rolePermissionPojo.getPermissionId());
                    }

                    StringBuffer permissionIdBuffer = new StringBuffer();
                    for(String value : permissionIdSet){
                        permissionIdBuffer.append("'" + value + "',");
                    }

                    String permissionIds = null;
                    if(permissionIdBuffer.length()>SysConstant.INT_ZERO){
                        permissionIds = permissionIdBuffer.substring(0,permissionIdBuffer.length()-1);
                    }

                    if(permissionIds!=null){
                        List<PermissionPojo> permissionPojoList = permissionService.queryPermissionPojoByIds(permissionIds);
                        if(permissionPojoList!=null && !permissionPojoList.isEmpty()){
                            for(PermissionPojo permissionPojo : permissionPojoList){
                                if(permissionPojo!=null && permissionPojo.getPermissionCode()!=null){
                                    permissions.add(permissionPojo.getPermissionCode());
                                }
                            }
                        }

                    }
                }
            }
        }

        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(roles);
        //添加权限
        info.setStringPermissions(permissions);

        // 返回认证对象
        return info;
    }

}
